import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ChargeStrategy } from 'src/entities/ChargeStrategy';
import { Device } from 'src/entities/Device';
import { ChargeStrategyModelService } from 'src/model/charge-strategy-model/charge-strategy-model.service';
import { DeviceModelService } from 'src/model/device-model/device-model.service';
import { DevicePortModelService } from 'src/model/device-port-model/device-port-model.service';
import { RedisService } from 'src/redis/redis.service';


interface DeviceRow extends Device {
    onlineStatus? : boolean;
}



@Injectable()
export class DeviceService {
    private deviceKey:string;
    private portKey:string;
    private strategryKey:string;

    constructor(
        private deviceModelService:DeviceModelService,
        private devicePortModelService:DevicePortModelService,
        private redis:RedisService,
        private configService:ConfigService,
        private chargeStrategyModelService:ChargeStrategyModelService,
    ) {
        this.deviceKey =  this.configService.get<string>('cacheKey.device')
        this.portKey =  this.configService.get<string>('cacheKey.port')
        this.strategryKey =  this.configService.get<string>('cacheKey.strategy')
    }
    
    async getDeviceById(deviceId:number) {
        const device = await this.device(deviceId)
        if(!device) return null

        const port = await this.port(deviceId)
        
        const strategy = device.strategyId ? await this.strategy(device.strategyId) : null

        let data:any = {
            device : {
                cate_1 : device.cate_1,
                cate_2 : device.cate_2,
                deviceName : device.deviceName
            },

            port

        }

        if(strategy) {
            data.strategy = {
                options : strategy.options,
                unitPrice : strategy.unitPrice,
                strategyType : strategy.strategyType,
                remark : strategy.remark,
            }

            if(strategy.rules) {
                let rules:any[] = []
                let len = (strategy.rules as any[]).length
                for(let i = 0; i < len;) {
                    let tmp = strategy.rules[i]
                    let _i = i + 1
                    if(_i >= len) {
                        rules.push(tmp)
                        break
                    }
                    for(; _i < len; _i ++) {
                        if(tmp.w != strategy.rules[_i].w) {
                            rules.push(tmp)
                            break
                        }
                    }
        
                    i = _i
                }

                data.strategy.rules = rules.map((rule, index) => ({min : index == 0 ? 0 : rules[index - 1].w, max : rule.w, amount : rule.a}))
            }
        }



        return data

        
    }

    async device(deviceId) {
        const deviceKey = this.deviceKey + deviceId
        let device = await this.redis.get<DeviceRow>(deviceKey)
        if(!device) {
            device = await this.deviceModelService.findOne({deviceId : deviceId}, ['cate_1', 'cate_2', 'connectStatus', 'deviceName', 'portCount', 'simId', 'simCardNo', 'merchantId', 'strategyId', 'longitude', 'latitude', 'address'])
            if(device) {
                this.redis.set(deviceKey, device)
            }
            
        }


        return device
    }

    async port(deviceId:number) {
        let devicePort:{portNo:number; status:number}[] = []
        let portKey = this.portKey + deviceId
        const ports:any = await this.redis.hgetall(portKey)
        if(ports) {
            for(let k in ports) {
                devicePort.push({portNo : Number(k), status : ports[k]})    
            }
        }else {
            devicePort = await this.devicePortModelService.find({deviceId : deviceId}, ['portNo', 'status'])
            if(devicePort) {
                let tmp:any[] = []
                devicePort.forEach(port => {
                    tmp.push(port.portNo, port.status)
                })
                this.redis.hmset(portKey, ...tmp)
            }
        }

        return devicePort
    }

    async strategy(strategyId:number) {
        let strategy:ChargeStrategy|null = null
        let strategryKey = this.strategryKey + strategyId
        strategy = await this.redis.get<ChargeStrategy>(strategryKey)
        if(!strategy) {
            strategy = await this.chargeStrategyModelService.findOne({strategyId : strategyId})
            if(strategy) {
                this.redis.set(strategryKey, strategy)
            }
        }

        return strategy
    }

    async getStrategyByDeviceId(deviceId:number) {
        const device = await this.device(deviceId)
        if(device || device.strategyId) {
            return this.strategy(device.strategyId)
        }

        return null
    }
}